package br.com.jparallelport.parallel;

import java.util.HashMap;
import java.util.Map;

public class ParallelPortLinux{
	public enum LEVEL{
		HIGH,
		LOW
	}

	public enum PARALLEL_MODEL {
		EPP,
		SPP
	}

	static {  
		System.loadLibrary("parallelPortLinux");  
	}  
	
	private static String lastWrite = "00000000";
	private static Map<Integer,Integer> mapPinMask = new HashMap<Integer, Integer>();
	private static final int INTERVAL_READ = 30;

	private short 	input;
	private long 	lastRead = 0;
	
	public ParallelPortLinux(){
		//SPP
		mapPinMask.put(10, 64);
		mapPinMask.put(12, 32);
		mapPinMask.put(13, 16);
		mapPinMask.put(15, 8);

		//EPP
		mapPinMask.put(2, 1);
		mapPinMask.put(3, 2);
		mapPinMask.put(4, 4);
		mapPinMask.put(5, 8);
	}

	public native char inb_wrapper(boolean epp);
	public native void outb_wrapper(char value);

	/**
	 * Pin write
	 */
	public void write(int pin, boolean value) {
		if(validatePinNumber(pin)){
			int pos = 8 - (pin - 1); 

			String left = lastWrite.substring(0, pos);
			String right = lastWrite.substring(pos+1, lastWrite.length());

			lastWrite = left + (value ? 1 : 0) + right;

			short valueOutput = Short.parseShort(lastWrite, 2);

			outb_wrapper((char)valueOutput);			
		}
	}

	/**
	 * Validate Pin
	 * @param pin
	 * @return
	 */
	private boolean validatePinNumber(int pin){
		if(!mapPinMask.containsKey(pin)){
			throw new IllegalArgumentException("Pino " + pin + " é invalido.");	
		}			
		return true;
	}

	/**
	 * Pin read 
	 */
	public boolean read(int pin, LEVEL level, PARALLEL_MODEL model) {
		if(validatePinNumber(pin)){
			long time = System.currentTimeMillis();
			
			if(Math.abs(time - lastRead) >= INTERVAL_READ){
				lastRead 	= time;
				input 		= (short)inb_wrapper(model == PARALLEL_MODEL.EPP ? true : false);	
			}
			
			int 	masc 	= mapPinMask.get(pin);
			boolean ret 	= (input & masc) == masc;

			if (level.equals(LEVEL.LOW))
				ret = !ret;

			return ret;	
		}

		return false;				
	}	

	public static void main(String args[]){
		ParallelPortLinux mwParallelPortLinux = new ParallelPortLinux();

		for (Integer pin : mapPinMask.keySet()) {
			boolean reading = false;
			if(pin >= 2 && pin <= 5)
				reading = mwParallelPortLinux.read(pin, LEVEL.HIGH, PARALLEL_MODEL.EPP);
			else
				reading = mwParallelPortLinux.read(pin, LEVEL.HIGH, PARALLEL_MODEL.SPP);

			System.out.println("Read - HIGH: " + pin + " - " + reading);
		}

		for (Integer pin : mapPinMask.keySet()) {
			boolean reading = false;
			if(pin>=2 && pin <= 5)
				reading = mwParallelPortLinux.read(pin, LEVEL.LOW, PARALLEL_MODEL.EPP);
			else
				reading = mwParallelPortLinux.read(pin, LEVEL.LOW, PARALLEL_MODEL.SPP);

			System.out.println("Read - LOW: " + pin + " - " + reading);
		}
	}
}
